#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    uint32_t w, h;
    uint8_t *data;
}image_t;

image_t imread(const char *fn)
{
    image_t im;
    FILE *fp = fopen(fn, "rb");
    char buf[256];
    fgets(buf, 256, fp);
    fgets(buf, 256, fp);
    fscanf(fp, "%d %d\n255\n", &im.w, &im.h);
    const uint32_t n = im.w * im.h * 3;
    im.data = malloc(n);
    fread(im.data, n, 1, fp);
    fclose(fp);
    return im;
}

void imwrite(const char *fn, const image_t im)
{
    FILE *fp = fopen(fn, "wb");
    fprintf(fp, "P6\n# Generated by zhaipro\n%d %d\n255\n", im.w, im.h);
    const uint32_t n = im.w * im.h * 3;
    fwrite(im.data, n, 1, fp);
    fclose(fp);
}

uint8_t max(uint8_t a, uint8_t b, uint8_t c)
{
    if(b > a) {
        a = b;
    }
    if(c > a) {
        a = c;
    }
    return a;
}

// https://www.mathworks.com/help/matlab/ref/rgb2gray.html
uint8_t rgb2gray(uint8_t r, uint8_t g, uint8_t b)
{
    return 0.299 * r + 0.587 * g + 0.114 * b;
}

void recolor(image_t im, image_t mask, double cr, double cg, double cb, double alpha)
{
    int i;
    int n = im.w * im.h;
    double m = max(cr, cg, cb);
    cr /= m;
    cg /= m;
    cb /= m;
    for(i=0; i<n; i++)
    {
        uint8_t r = im.data[i * 3], g = im.data[i * 3 + 1], b = im.data[i * 3 + 2];
        m = rgb2gray(mask.data[i * 3], mask.data[i * 3 + 1], mask.data[i * 3 + 2]);
        m /= 255;
        double x = max(r, g, b);
        x = 255 - 255 * pow(1 - x / 255, alpha);
        im.data[i * 3 + 0] = r * (1 - m) + x * cr * m;
        im.data[i * 3 + 1] = g * (1 - m) + x * cg * m;
        im.data[i * 3 + 2] = b * (1 - m) + x * cb * m;
    }
}

int main(int argc , char *argv[])
{
    double alpha;
    sscanf(argv[1], "%lf", &alpha);
    uint8_t r = 0x66, g = 0x16, b = 0x40;
    image_t im, mask;
    im = imread("14.ppm");
    mask = imread("mask.ppm");
    recolor(im, mask, r, g, b, alpha);
    imwrite("result.ppm", im);
    free(im.data);
    free(mask.data);
    return 0;
}
